﻿/*
 * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
 * See https://github.com/openiddict/openiddict-core for more information concerning
 * the license and the contributors participating to this project.
 */

using System.ComponentModel;
using OpenIddict.Client.WebIntegration;

#if SUPPORTS_PEM_ENCODED_KEY_IMPORT
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
#endif

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Exposes the necessary methods required to configure the OpenIddict client services.
/// </summary>
public sealed partial class OpenIddictClientWebIntegrationBuilder
{
    /// <summary>
    /// Initializes a new instance of <see cref="OpenIddictClientWebIntegrationBuilder"/>.
    /// </summary>
    /// <param name="services">The services collection.</param>
    public OpenIddictClientWebIntegrationBuilder(IServiceCollection services)
        => Services = services ?? throw new ArgumentNullException(nameof(services));

    /// <summary>
    /// Gets the services collection.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public IServiceCollection Services { get; }

    /// <summary>
    /// Amends the default OpenIddict client Web integration configuration.
    /// </summary>
    /// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
    /// <remarks>This extension can be safely called multiple times.</remarks>
    /// <returns>The <see cref="OpenIddictClientWebIntegrationBuilder"/> instance.</returns>
    public OpenIddictClientWebIntegrationBuilder Configure(Action<OpenIddictClientWebIntegrationOptions> configuration)
    {
        if (configuration is null)
        {
            throw new ArgumentNullException(nameof(configuration));
        }

        Services.Configure(configuration);

        return this;
    }

    // Note: provider registration methods are automatically generated by the source generator.

    /// <summary>
    /// Exposes the necessary methods required to configure the Apple integration.
    /// </summary>
    public partial class Apple
    {
#if SUPPORTS_PEM_ENCODED_KEY_IMPORT
        /// <summary>
        /// Configures the Elliptic Curve Digital Signature Algorithm
        /// (ECDSA) signing key associated with the developer account.
        /// </summary>
        /// <param name="key">
        /// The PEM-encoded Elliptic Curve Digital Signature Algorithm
        /// (ECDSA) signing key associated with the developer account.
        /// </param>
        /// <returns>The <see cref="Apple"/> instance.</returns>
        public Apple SetSigningKey(string key) => SetSigningKey(key.AsMemory());

        /// <summary>
        /// Configures the Elliptic Curve Digital Signature Algorithm
        /// (ECDSA) signing key associated with the developer account.
        /// </summary>
        /// <param name="key">
        /// The PEM-encoded Elliptic Curve Digital Signature Algorithm
        /// (ECDSA) signing key associated with the developer account.
        /// </param>
        /// <returns>The <see cref="Apple"/> instance.</returns>
        public Apple SetSigningKey(ReadOnlyMemory<char> key) => SetSigningKey(key.Span);

        /// <summary>
        /// Configures the Elliptic Curve Digital Signature Algorithm
        /// (ECDSA) signing key associated with the developer account.
        /// </summary>
        /// <param name="key">
        /// The PEM-encoded Elliptic Curve Digital Signature Algorithm
        /// (ECDSA) signing key associated with the developer account.
        /// </param>
        /// <returns>The <see cref="Apple"/> instance.</returns>
        public Apple SetSigningKey(ReadOnlySpan<char> key)
        {
            if (key.IsEmpty)
            {
                throw new ArgumentException(SR.GetResourceString(SR.ID0346), nameof(key));
            }

            var algorithm = OpenIddictHelpers.CreateEcdsaKey();

            try
            {
                algorithm.ImportFromPem(key);
            }

            catch
            {
                algorithm.Dispose();

                throw;
            }

            return SetSigningKey(new ECDsaSecurityKey(algorithm));
        }
#endif
    }

    /// <inheritdoc/>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public override bool Equals(object? obj) => base.Equals(obj);

    /// <inheritdoc/>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public override int GetHashCode() => base.GetHashCode();

    /// <inheritdoc/>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public override string? ToString() => base.ToString();
}
